package com.ziiwee.reduce.describe.register;

import com.ziiwee.reduce.commons.utils.ExportUtil;
import com.ziiwee.reduce.describe.ControllerDescribe;
import com.ziiwee.reduce.describe.DescribeException;
import com.ziiwee.reduce.describe.creators.controllers.DefaultControllerDescribeCreator;
import com.ziiwee.reduce.describe.creators.controllers.ResourceControllerControllerDescribeCreator;
import com.ziiwee.reduce.describe.utils.DescribeUtil;
import com.ziiwee.reduce.rest.ResourceController;
import org.springframework.context.ApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.*;

/**
 * @author ziiwee
 * @date 2020/8/13
 */
public class DefaultRequestMappingDescribeRegister implements RequestMappingDescribeRegister {

    private final Set<ControllerDescribe> set = new HashSet<>();

    private final ApplicationContext applicationContext;

    private final int order;

    public DefaultRequestMappingDescribeRegister(ApplicationContext applicationContext, int order) {
        this.applicationContext = applicationContext;
        this.order = order;
    }

    @Override
    public void register(RequestMappingHandlerMapping mapping) {
        Map<Class<?>, Map<RequestMappingInfo, HandlerMethod>> map = new HashMap<>();
        mapping.getHandlerMethods().forEach((k, v) -> {
            if (ExportUtil.isMethodExport(v.getBeanType(), v.getMethod())) {
                Map<RequestMappingInfo, HandlerMethod> value = map.get(v.getBeanType());
                value = value != null ? value : new HashMap<>();
                value.put(k, v);
                map.put(v.getBeanType(), value);
            }
        });
        map.forEach(this::registerHandler);
    }

    private void registerHandler(Class<?> beanType, Map<RequestMappingInfo, HandlerMethod> map) {
        Object bean = applicationContext.getBean(beanType);
        if (bean instanceof ResourceController) {
//            ResourceController<?, ?> controller = (ResourceController<?, ?>) bean;
            List<ResolvableType> args = DescribeUtil.getTypeArgsByResolvableType(ResolvableType.forClass(beanType), ResourceController.class);
            if (args.size() != 2) {
                throw new DescribeException("无法获取泛型参数:" + beanType);
            }
            ResolvableType type = ResolvableType.forInstance(bean);
            set.add(new ResourceControllerControllerDescribeCreator((ResourceController<?, ?>) bean, type, map).create());
        } else {
            set.add(new DefaultControllerDescribeCreator(beanType, map).create());
        }
    }

    @Override
    public int getOrder() {
        return order;
    }

    @Override
    public Collection<ControllerDescribe> getDescribes() {
        return set;
    }
}
